import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext
import threading
import os
import logging

logger = logging.getLogger(__name__)


class FileDownload:
    def __init__(self, main_window):
        self.main_window = main_window
        self.remote_path_text = None
        self.local_path_entry = None

    def create_download_frame(self, parent_frame):
        """创建下载区域框架"""
        download_frame = ttk.LabelFrame(parent_frame, text="文件下载", padding="10 5 10 5")
        download_frame.pack(fill=tk.X, padx=10, pady=5)
        download_frame.grid_columnconfigure(1, weight=1)
        download_frame.configure(height=220)

        ttk.Label(download_frame, text="远程文件路径:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
        self.remote_path_text = scrolledtext.ScrolledText(download_frame, height=8, wrap=tk.WORD)
        self.remote_path_text.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ttk.Button(download_frame, text="下载", command=self.download_file).grid(row=0, column=2, padx=5, pady=5, sticky="ew")
        ttk.Label(download_frame, text="本地保存路径:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
        self.local_path_entry = ttk.Entry(download_frame)
        self.local_path_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ttk.Button(download_frame, text="浏览", command=self.browse_download_path).grid(row=1, column=2, padx=5, pady=5, sticky="ew")

    def browse_download_path(self):
        """选择本地保存路径"""
        path = filedialog.askdirectory()
        if path:
            self.local_path_entry.delete(0, tk.END)
            self.local_path_entry.insert(0, path)
            logger.info(f"本地保存路径已设置为: {path}")

    def download_file(self):
        """多线程批量下载文件/目录从多个服务器"""
        logger.info("尝试批量下载文件/目录...")
        remote_paths_text = self.remote_path_text.get(1.0, tk.END).strip()
        local_path = self.local_path_entry.get().strip()

        if not remote_paths_text or not local_path:
            self.main_window.show_message("请填写远程路径和本地保存路径")
            logger.warning("下载文件：远程路径或本地保存路径为空")
            return

        # 解析远程路径，支持多行输入
        remote_paths = [path.strip() for path in remote_paths_text.split('\n') if path.strip()]
        
        if not remote_paths:
            self.main_window.show_message("请输入有效的远程路径")
            logger.warning("下载文件：请输入有效的远程路径")
            return

        # 获取所有选中且已连接的服务器
        selected_servers = []
        for item in self.main_window.server_connection.server_table.get_children():
            values = self.main_window.server_connection.server_table.item(item, "values")
            if values[0] == "√" and values[5] in ["已连接", "已连接(develop)", "已连接(缓存)"]:
                ip = values[1]
                if ip in self.main_window.server_connection.ssh_sessions:
                    selected_servers.append(ip)

        if not selected_servers:
            self.main_window.show_message("请选择已连接的服务器")
            logger.warning("下载文件：没有选中的已连接服务器")
            return

        # 确保本地保存目录存在
        try:
            os.makedirs(local_path, exist_ok=True)
            logger.info(f"确保本地保存目录存在: {local_path}")
        except Exception as e:
            self.main_window.show_message(f"创建本地目录失败: {str(e)}")
            logger.error(f"创建本地目录 {local_path} 失败: {e}", exc_info=True)
            return

        # 显示开始下载信息
        self.main_window.show_message(f"开始从 {len(selected_servers)} 个服务器下载 {len(remote_paths)} 个路径")
        logger.info(f"开始从 {len(selected_servers)} 个服务器下载 {len(remote_paths)} 个路径")
        
        # 为每个服务器创建下载线程
        download_threads = []
        for ip in selected_servers:
            thread = threading.Thread(
                target=self._download_files_from_server,
                args=(ip, remote_paths, local_path),
                name=f"Download-{ip}"
            )
            thread.daemon = True
            download_threads.append(thread)
            thread.start()
            
        # 更新服务器状态为下载中
        for item in self.main_window.server_connection.server_table.get_children():
            values = list(self.main_window.server_connection.server_table.item(item, "values"))
            if values[1] in selected_servers:
                values[8] = "下载中..."
                self.main_window.server_connection.server_table.item(item, values=values)
                logger.info(f"设置服务器 {values[1]} 状态为 '下载中...' ")

    def _download_files_from_server(self, ip, remote_paths, local_base_dir):
        """从单个服务器下载文件/目录"""
        logger.info(f"开始从服务器 {ip} 下载文件/目录")
        download_success = 0
        download_failed = 0
        
        try:
            ssh = self.main_window.server_connection.ssh_sessions[ip]['ssh']
            sftp = ssh.open_sftp()
            logger.info(f"已创建SFTP客户端到 {ip}")

            # 为每个服务器创建独立的下载目录
            server_local_dir = os.path.join(local_base_dir, f"server_{ip}")
            server_local_dir = server_local_dir.replace('/',os.sep)
            os.makedirs(server_local_dir, exist_ok=True)
            logger.info(f"为 {ip} 创建本地下载目录: {server_local_dir}")

            self.main_window.server_connection.append_to_terminal(ip, f"\n=== 开始下载 {len(remote_paths)} 个路径到 {server_local_dir} ===\n")
            logger.info(f"从 {ip} 下载 {len(remote_paths)} 个路径到 {server_local_dir}")

            for i, remote_path in enumerate(remote_paths, 1):
                remote_path = remote_path.strip()
                if not remote_path:
                    logger.warning(f"从 {ip} 下载：跳过空远程路径")
                    continue

                try:
                    # 标准化Linux路径（将Windows路径分隔符转换为Linux格式）
                    remote_path = remote_path.replace('\\', '/')
                    
                    self.main_window.server_connection.append_to_terminal(ip, f"[{i}/{len(remote_paths)}] 正在处理: {remote_path}\n")
                    logger.info(f"处理下载路径 {remote_path} from {ip}")
                    
                    # 检查远程路径是否存在
                    try:
                        stat_info = sftp.stat(remote_path)
                        is_directory = stat_info.st_mode & 0o40000
                        logger.debug(f"远程路径 {remote_path} 类型: {'目录' if is_directory else '文件'}")
                    except FileNotFoundError:
                        self.main_window.server_connection.append_to_terminal(ip, f"  ❌ 路径不存在: {remote_path}\n")
                        logger.error(f"从 {ip} 下载失败：远程路径不存在: {remote_path}")
                        download_failed += 1
                        continue
                    except Exception as e:
                        self.main_window.server_connection.append_to_terminal(ip, f"  ❌ 无法访问路径: {remote_path}, 错误: {str(e)}\n")
                        logger.error(f"从 {ip} 下载失败：无法访问路径 {remote_path}, 错误: {e}", exc_info=True)
                        download_failed += 1
                        continue

                    # 生成本地路径（处理Windows路径分隔符）
                    remote_basename = os.path.basename(remote_path.rstrip('/'))
                    if not remote_basename:  # 处理根目录情况
                        remote_basename = remote_path.replace('/', '_')
                    
                    local_target_path = os.path.join(server_local_dir, remote_basename)
                    local_target_path  = local_target_path.replace('/', '\\')
                    logger.debug(f"远程路径 {remote_path} 映射到本地路径: {local_target_path}")

                    if is_directory:
                        # 下载目录
                        self.main_window.server_connection.append_to_terminal(ip, f"  📁 下载目录: {remote_path}\n")
                        logger.info(f"开始从 {ip} 下载目录: {remote_path} -> {local_target_path}")
                        success = self._download_directory_recursive(ip, sftp, remote_path, local_target_path)
                        if success:
                            download_success += 1
                            print(f"  ✅ 目录下载完成: {remote_path} -> {local_target_path}")
                            self.main_window.server_connection.append_to_terminal(ip, f"  ✅ 目录下载完成: {remote_path} -> {local_target_path}\n")
                            logger.info(f"从 {ip} 下载目录 {remote_path} 完成")
                        else:
                            download_failed += 1
                            logger.error(f"从 {ip} 下载目录 {remote_path} 失败")
                    else:
                        # 下载文件
                        self.main_window.server_connection.append_to_terminal(ip, f"  📄 下载文件: {remote_path}\n")
                        logger.info(f"开始从 {ip} 下载文件: {remote_path} -> {local_target_path}")
                        try:
                            # 确保本地目录存在
                            os.makedirs(os.path.dirname(local_target_path), exist_ok=True)
                            sftp.get(remote_path, local_target_path)
                            download_success += 1
                            self.main_window.server_connection.append_to_terminal(ip, f"  ✅ 文件下载完成: {remote_path} -> {local_target_path}\n")
                            logger.info(f"从 {ip} 下载文件 {remote_path} 完成")
                        except Exception as e:
                            download_failed += 1
                            self.main_window.server_connection.append_to_terminal(ip, f"  ❌ 文件下载失败: {remote_path}, 错误: {str(e)}\n")
                            logger.error(f"从 {ip} 下载文件 {remote_path} 失败: {e}", exc_info=True)

                except Exception as e:
                    download_failed += 1
                    self.main_window.server_connection.append_to_terminal(ip, f"  ❌ 处理路径时出错: {remote_path}, 错误: {str(e)}\n")
                    logger.error(f"从 {ip} 下载：处理路径 {remote_path} 时出错: {e}", exc_info=True)

            # 下载完成统计
            self.main_window.server_connection.append_to_terminal(ip, f"\n=== 下载完成统计 ===\n")
            self.main_window.server_connection.append_to_terminal(ip, f"成功: {download_success} 个\n")
            self.main_window.server_connection.append_to_terminal(ip, f"失败: {download_failed} 个\n")
            self.main_window.server_connection.append_to_terminal(ip, f"保存位置: {server_local_dir}\n")
            logger.info(f"从 {ip} 下载完成统计：成功 {download_success} 个，失败 {download_failed} 个")

            sftp.close()
            logger.info(f"从 {ip} 的SFTP客户端已关闭")
            
        except Exception as e:
            self.main_window.server_connection.append_to_terminal(ip, f"❌ 连接错误: {str(e)}\n")
            logger.critical(f"从 {ip} 下载文件时出现连接错误: {e}", exc_info=True)
            download_failed = len(remote_paths)
        
        finally:
            # 更新服务器状态
            self._update_server_download_status(ip, download_success, download_failed)
            logger.info(f"已更新 {ip} 的下载状态")
    
    def _update_server_download_status(self, ip, success_count, failed_count):
        """更新服务器下载状态"""
        try:
            for item in self.main_window.server_connection.server_table.get_children():
                values = list(self.main_window.server_connection.server_table.item(item, "values"))
                if values[1] == ip:
                    if failed_count == 0:
                        values[8] = f"下载完成({success_count}个)"
                        logger.info(f"服务器 {ip} 下载状态更新为：完成({success_count}个)")
                    else:
                        values[8] = f"下载完成({success_count}成功,{failed_count}失败)"
                        logger.warning(f"服务器 {ip} 下载状态更新为：完成({success_count}成功,{failed_count}失败)")
                    self.main_window.server_connection.server_table.item(item, values=values)
                    break
        except Exception as e:
            logger.error(f"更新服务器 {ip} 下载状态失败: {e}", exc_info=True)
            print(f"更新服务器状态失败: {e}")

    def _download_directory_recursive(self, ip, sftp, remote_dir, local_dir):
        """递归下载整个目录"""
        logger.info(f"开始递归下载目录: {ip}:{remote_dir} -> {local_dir}")
        try:
            # 创建本地目录
            os.makedirs(local_dir, exist_ok=True)
            logger.debug(f"确保本地目录存在: {local_dir}")
            
            # 标准化远程目录路径
            remote_dir = remote_dir.rstrip('/')
            
            # 获取目录内容
            try:
                items = sftp.listdir(remote_dir)
                logger.debug(f"列出目录 {remote_dir} 内容: {items}")
            except Exception as e:
                self.main_window.server_connection.append_to_terminal(ip, f"    ❌ 无法列出目录内容: {remote_dir}, 错误: {str(e)}\n")
                logger.error(f"无法列出 {ip} 的目录内容: {remote_dir}, 错误: {e}", exc_info=True)
                return False
            
            if not items:
                self.main_window.server_connection.append_to_terminal(ip, f"    📁 空目录: {remote_dir}\n")
                logger.info(f"目录 {remote_dir} 为空")
                return True
            
            success_count = 0
            total_count = len(items)
            logger.debug(f"目录 {remote_dir} 共有 {total_count} 个项目")
            
            for item in items:
                # 构建远程和本地路径
                remote_item_path = f"{remote_dir}/{item}"
                local_item_path = os.path.join(local_dir, item)
                
                try:
                    # 获取文件/目录信息
                    stat_info = sftp.stat(remote_item_path)
                    is_directory = stat_info.st_mode & 0o40000
                    
                    if is_directory:
                        # 递归下载子目录
                        self.main_window.server_connection.append_to_terminal(ip, f"    📁 进入子目录: {remote_item_path}\n")
                        logger.info(f"递归进入子目录: {ip}:{remote_item_path}")
                        if self._download_directory_recursive(ip, sftp, remote_item_path, local_item_path):
                            success_count += 1
                    else:
                        # 下载文件
                        try:
                            sftp.get(remote_item_path, local_item_path)
                            success_count += 1
                            file_size = stat_info.st_size
                            self.main_window.server_connection.append_to_terminal(ip, f"    ✅ 文件: {item} ({self._format_file_size(file_size)})\n")
                            logger.info(f"已下载文件: {item} ({self._format_file_size(file_size)})")
                        except Exception as e:
                            self.main_window.server_connection.append_to_terminal(ip, f"    ❌ 下载文件失败: {item}, 错误: {str(e)}\n")
                            logger.error(f"从 {ip} 下载文件 {remote_item_path} 失败: {e}", exc_info=True)
                            
                except Exception as e:
                    self.main_window.server_connection.append_to_terminal(ip, f"    ❌ 处理项目失败: {item}, 错误: {str(e)}\n")
                    logger.error(f"处理 {ip} 的目录项目 {item} 失败: {e}", exc_info=True)
            
            # 返回是否全部成功
            result = success_count == total_count
            logger.info(f"目录 {remote_dir} 递归下载完成，结果: {'成功' if result else '失败'}")
            return result
            
        except Exception as e:
            self.main_window.server_connection.append_to_terminal(ip, f"    ❌ 下载目录失败: {remote_dir}, 错误: {str(e)}\n")
            logger.error(f"递归下载目录 {ip}:{remote_dir} 失败: {e}", exc_info=True)
            return False
    
    def _format_file_size(self, size_bytes):
        """格式化文件大小显示"""
        if size_bytes == 0:
            return "0B"
        size_names = ["B", "KB", "MB", "GB", "TB"]
        import math
        i = int(math.floor(math.log(size_bytes, 1024)))
        p = math.pow(1024, i)
        s = round(size_bytes / p, 2)
        return f"{s} {size_names[i]}" 